/**
 * @YAMLUnitSourceGroupManager.java  COPYRIGHT xiaojian
 * 
 * Created on 2017年10月27日 下午3:03:36
 */
package xiaojian.toolkit.ebus.unit.yaml;

import java.io.InputStream;
import java.util.Timer;
import java.util.TimerTask;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;

import xiaojian.toolkit.ebus.EventBus;

/**
 * 使用YAML作为配置文件格式，将所有配置文件合并到一个YAML文件里面。
 * 
 * @author <a href="mailto:cxj2000@gmail.com">xiaojian.cao</a>
 *
 */
public class YAMLUnitSourceGroupManager {

	private static final Logger logger = LoggerFactory.getLogger(YAMLUnitSourceGroupManager.class);

	private EventBus eventBus;
	private String eventUnitsChanged = "com.skymobi.event.unit";

	private Resource location;
	private long locationLastModified = 0L;
	private Units lastSnapshot = null;

	private final Timer timer = new Timer(false);

	private final boolean enabled;

	public EventBus getEventBus() {
		return eventBus;
	}

	public void setEventBus(EventBus eventBus) {
		this.eventBus = eventBus;
	}

	public Resource getLocation() {
		return location;
	}

	public void setLocation(Resource location) {
		this.location = location;
	}

	public YAMLUnitSourceGroupManager(final boolean enabled) {
		this.enabled = enabled;
	}

	public void start() throws Exception {
		if (!this.enabled) {
			return;
		}

		this.scheduleRebuild(0);

	}

	private void scheduleRebuild(final long delay) {
		this.timer.schedule(new TimerTask() {
			@Override
			public void run() {
				try {
					rebuildUnits();
				} catch (Exception e) {
					logger.warn("exception when rebuildUnits.", e);
				}
			}
		}, delay);
	}

	private void rebuildUnits() throws Exception {

		if (this.locationLastModified == this.location.lastModified()) {
			scheduleRebuild(1000L);
			return;
		}

		this.locationLastModified = this.location.lastModified();
		final Yaml yaml = new Yaml(new Constructor(Units.class));

		try {
			InputStream is = this.location.getInputStream();
			Units units = (Units) yaml.load(is);
			if (logger.isDebugEnabled()) {
				logger.debug("load unit description from location[{}]\n{}", this.location, units);
			}
			build(units);
		} finally {
			scheduleRebuild(1000L);
		}
	}

	public void stop() {
		this.timer.cancel();
	}

	/**
	 * 
	 * @param units
	 */
	private void build(Units units) {
		if (lastSnapshot != null) {
			for (YamlUnitSource us : units.getUnits()) {
				YamlUnitSource other = this.lastSnapshot.getUnitSourceByName(us.getName());
				if (other == null) {
					us.updateLastModified();
				}
				
				if (other != null && !other.equals(us)) {
					us.updateLastModified();
				}
				
				if (other != null && other.equals(us)) {
					us.setLastModified(other.lastModified());
				}
			}
		}

		eventBus.fireEvent(eventUnitsChanged, "YAML_UNITS", units.getUnits().iterator());
		lastSnapshot = units;
	}
}
